<?php
namespace App\Services;

use App\BaseDictionary;
use App\UserGroup;
use App\User;
use App\GroupUser;
use App\PartnerGroupType;
use App\PartnerGroupTypePermission;
use App\UserRole;
use App\Role;
use App\RoleMenuPermission;
use App\Lib\Util\QueryPager;
use App\Lib\Auth\CurrentUserGroupTrait;
use DB;

class UserGroupService
{
    use CurrentUserGroupTrait;

    public function createUserGroup($userGroup)
    {
        return UserGroup::create($userGroup);
    }

    private function baseQuery()
    {
        return UserGroup::select('id', 'name', 'code', 'business_code', 'group_type', 'active_status',
            'manager_id', 'partner_group_type_id', 'sort_order', 'province_id', 'city_id', 'district_id', 'detailed_address', 'icon')
            ->with('manager', 'parent', 'partnerGroupType', 'province', 'city', 'district');
    }

    public function getGroups(Array $input, $paging = true)
    {
        $query = $this->baseQuery();

        if (!empty($input['activeStatus'])) {
            $query = $query->where('active_status', $input['activeStatus']);
        }

        if (!empty($input['parentId'])) {
            $query = $query->where('parent_id', $input['parentId']);
        } else if (isset($input['parentId'])) {
            if ($input['parentId'] === '') {
                $query = $query->whereNull('parent_id');
            }
        }

        if (!empty($input['name'])) {
            $query = $query->where('name', 'like' , '%'.$input['name'].'%');
        }

        if (!empty($input['code'])) {
            $query = $query->where('code', 'like' , '%'.$input['code'].'%');
        }

        if (!empty($input['businessCode'])) {
            $query = $query->where('business_code', 'like' , '%'.$input['businessCode'].'%');
        }

        if (!empty($input['groupType'])) {
            $query = $query->where('group_type', $input['groupType']);
        }

        if (!empty($input['partnerGroupTypeId'])) {
            $query = $query->where('partner_group_type_id', $input['partnerGroupTypeId']);
        }

        if (!empty($input['provinceId'])) {
            $query = $query->where('province_id', $input['provinceId']);
        }

        if (!empty($input['cityId'])) {
            $query = $query->where('city_id', $input['cityId']);
        }

        $pager = new QueryPager($query);

        $pager->mapField('active_status', UserGroup::$GROUP_STATUS_MAP);
        $pager->mapField('group_type', UserGroup::$GROUP_TYPE_MAP);

        $pager->setRefectionMethodField('getFullIconPath');
        $pager->setRefectionMethodField('getFullAddress');

        return $paging ? $pager->doPaginate($input, 'sort_order') :
            $pager->queryWithoutPaginate($input, 'sort_order');
    }

    public function saveNewPartnerGroupWithManager($data, $groupType)
    {
        DB::transaction(function () use ($data, $groupType) {
            $partnerGroup = UserGroup::create([
                'name' => $data['name'],
                'code' => $this->getNewGroupCode(),
                'group_type' => $groupType,
                'business_code' => isset($data['business_code'])?$data['business_code']:null,
                'icon' => $data['icon'],
                'partner_group_type_id' => $data['partner_group_type_id'],
                'province_id' => $data['province_id'],
                'city_id' => $data['city_id'],
                'district_id' => $data['district_id'],
                'detailed_address' => $data['detailed_address'],
                'sort_order' => $data['sort_order'],
                'active_status' => UserGroup::$GROUP_STATUS_ACTIVE,
            ]);

            $user = $this->getUserByMobile($data['manager_mobile'], $data['manager_name'], $data['manager_nickname']);

            $user->password = $data['manager_password'];
            $user->save();

            if (GroupUser::where('user_id', $user->id)->where('is_primary_group', BaseDictionary::$KEY_YES)->count() > 0) {
                //已经存在当前用户的主用户组，则当前用户组不设为该用户的主用户组
                $isPrimaryGroup = BaseDictionary::$KEY_NO;
            } else {
                //不存在当前用户的主用户组，则将当前用户组设为该用户的主用户组
                $isPrimaryGroup = BaseDictionary::$KEY_YES;
            }

            GroupUser::create([
                'user_id' => $user->id,
                'group_id' => $partnerGroup->id,
                'is_primary_group' => $isPrimaryGroup
            ]);

            $partnerGroup->manager_id = $user->id;
            $partnerGroup->save();

            $role = $this->getDefaultAdminRole($partnerGroup);

            UserRole::create([
                'user_id' => $user->id,
                'role_id' => $role->id
            ]);
        });
    }

    public function saveUpdatePartnerGroupWithManager($data, $groupType)
    {
        DB::transaction(function () use ($data, $groupType) {
            $partnerGroup = UserGroup::findOrFail($data['id']);
            $partnerGroup->update([
                'id' => $data['id'],
                'name' => $data['name'],
                'group_type' => $groupType,
                'business_code' => isset($data['business_code'])?$data['business_code']:null,
                'icon' => $data['icon'],
                'partner_group_type_id' => $data['partner_group_type_id'],
                'province_id' => $data['province_id'],
                'city_id' => $data['city_id'],
                'district_id' => $data['district_id'],
                'detailed_address' => $data['detailed_address']
            ]);

            $user = $this->getUserByMobile($data['manager_mobile'], $data['manager_name'], $data['manager_nickname']);
            $user->password = $data['manager_password'];
            $user->save();

            if (GroupUser::where('user_id', $user->id)->where('group_id', $partnerGroup->id)->count() == 0) {
                if (GroupUser::where('user_id', $user->id)->where('is_primary_group', BaseDictionary::$KEY_YES)->count() > 0) {
                    //已经存在当前用户的主用户组，则当前用户组不设为该用户的主用户组
                    $isPrimaryGroup = BaseDictionary::$KEY_NO;
                } else {
                    //不存在当前用户的主用户组，则将当前用户组设为该用户的主用户组
                    $isPrimaryGroup = BaseDictionary::$KEY_YES;
                }

                GroupUser::create([
                    'user_id' => $user->id,
                    'group_id' => $partnerGroup->id,
                    'is_primary_group' => $isPrimaryGroup
                ]);
            }

            $partnerGroup->manager_id = $user->id;
            $partnerGroup->save();

            $role = $this->getDefaultAdminRole($partnerGroup);

            if (UserRole::where('user_id', $user->id)->where('role_id', $role->id)->count() == 0) {
                UserRole::create([
                    'user_id' => $user->id,
                    'role_id' => $role->id
                ]);
            }
        });
    }

    private function getDefaultAdminRole($group)
    {
        $groupId = $group->id;

        $roleName = config('system.default_admin_role_name');

        $role = Role::where('name', $roleName)->where('group_id', $groupId)->first();

        if (empty($role)) {
            $role = Role::create([
                'name' => $roleName,
                'group_id' => $groupId,
            ]);
        }

        if (!empty($group->partner_group_type_id)) {
            $permissions = PartnerGroupTypePermission::where('group_type_id', $group->partner_group_type_id)->get();

            RoleMenuPermission::where('role_id', $role->id)->delete();

            foreach ($permissions as $permission) {
                RoleMenuPermission::create([
                    'role_id' => $role->id,
                    'permission_id' => $permission->permission_id
                ]);
            }
        }

        return $role;
    }

    private function getUserByMobile($mobile, $name, $nickname)
    {
        $user = User::where('mobile', $mobile)->first();

        if (!empty($user)) {
            //原用户登录名同手机号一致，但传入的用户登录名存在，则修改该用户登录名为传入值
            if ($user->name === $user->mobile && !empty($name)) {
                //新用户登录名在系统里不存在（唯一的）
                if (User::where('name', $name)
                    ->where('mobile', '<>', $mobile)->count() == 0) {
                    $user->name = $name;
                }
            }

            //原用户昵称同手机号一致，但传入的用户昵称存在，则修改该用户昵称为传入值
            if ($user->nick_name === $user->mobile && !empty($nickname)) {
                $user->nick_name = $nickname;
            }

            $user->user_active = User::$USER_STATUS_ACTIVE;
            $user->save();
        } else {
            $user = User::create([
                'mobile' => $mobile,
                'name' => (empty($name)?$mobile:$name),
                'nick_name' => (empty($nickname)?$mobile:$nickname),
            ]);

            $user->is_super = BaseDictionary::$KEY_NO;
            $user->user_active = User::$USER_STATUS_ACTIVE;
            $user->save();
        }

        return $user;
    }

    public function getCascadeInternalGroups()
    {
        $depOrgs = UserGroup::select('id', 'name', 'code', 'parent_id')
            ->whereIn('group_type', [
                UserGroup::$GROUP_TYPE_INTERNAL_ORGANIZATION,
                UserGroup::$GROUP_TYPE_INTERNAL_DEPARTMENT
            ])->where('active_status', UserGroup::$GROUP_STATUS_ACTIVE)
            ->orderBy('sort_order')->get()->toArray();

        return $this->getChildGroups($depOrgs, null);
    }

    public function getPossiableParentGroups($parent)
    {
        if (isset($parent)) {
            if (!empty($parent->parent_id)) {
                return UserGroup::where('active_status', UserGroup::$GROUP_STATUS_ACTIVE)
                    ->whereIn('group_type', [
                        UserGroup::$GROUP_TYPE_INTERNAL_ORGANIZATION,
                        UserGroup::$GROUP_TYPE_INTERNAL_DEPARTMENT
                    ])
                    ->where('parent_id', $parent->parent_id)
                    ->orderBy('sort_order')->get();
            }
        }

        return UserGroup::where('active_status', UserGroup::$GROUP_STATUS_ACTIVE)
            ->where('group_type', UserGroup::$GROUP_TYPE_INTERNAL_ORGANIZATION)
            ->whereNull('parent_id')
            ->orderBy('sort_order')->get();
    }

    private function getChildGroups($depOrgs, $parentOrg)
    {
        $children = [];

        $depOrgCount = count($depOrgs);

        for ($i=0; $i<$depOrgCount; $i++) {
            $depOrg = $depOrgs[$i];

            if  ($parentOrg === null) {
                if (empty($depOrg['parent_id'])) {
                    $currentOrg = $depOrg;
                    array_push($children, $currentOrg);
                    unset($depOrgs[$i]);
                }
            } else {
                if ($depOrg['parent_id'] == $parentOrg['id']) {
                    $currentOrg = $depOrg;
                    array_push($children, $currentOrg);
                    unset($depOrgs[$i]);
                }
            }
        }

        $result = [];

        $childrenCount = count($children);
        if ($childrenCount > 0) {
            $depOrgs = array_values($depOrgs);

            for ($i=0; $i<$childrenCount; $i++) {
                $currentOrg = $children[$i];

                array_push($result, array_merge($currentOrg, [
                    'spread' => true,
                    'children' => $this->getChildGroups($depOrgs, $currentOrg)
                ]));
            }
        }

        return $result;
    }

    public function getNewGroupCode()
    {
        if (UserGroup::count() > 0) {
            $lastCode = UserGroup::whereIn('group_type', [
                UserGroup::$GROUP_TYPE_EXTERNAL_ENTERPRISE,
                UserGroup::$GROUP_TYPE_INTERNAL_ORGANIZATION,
                UserGroup::$GROUP_TYPE_USER
            ])->whereNull('parent_id')->max('code');

            $codeVal = intval($lastCode);

            $nextVal = $codeVal + 1;

            $strCodeVal = strval($nextVal);

            $len = 12 - strlen($strCodeVal);

            for ($i=0; $i<$len; $i++) {
                $strCodeVal = '0'.$strCodeVal;
            }

            return $strCodeVal;
        }

        return '000000000001';
    }

    public function getNewChildGroupCode($parentId)
    {
        $parentGroup = UserGroup::findOrFail($parentId);

        $childCounts = UserGroup::where('parent_id', $parentId)->count();

        if ($childCounts > 0) {
            $lastCode = UserGroup::where('parent_id', $parentId)->max('code');
            $fields = explode('-', $lastCode);
            $lastField = $fields[count($fields)-1];

            $codeVal = intval($lastField);

            $nextVal = $codeVal + 1;

            $strCodeVal = strval($nextVal);

            $len = 3 - strlen($strCodeVal);

            for ($i=0; $i<$len; $i++) {
                $strCodeVal = '0'.$strCodeVal;
            }

            return $parentGroup->code.'-'.$strCodeVal;
        }

        return $parentGroup->code.'-001';
    }

    public function hasChildren($groupId)
    {
        return UserGroup::where('parent_id', $groupId)->count() > 0;
    }

    public function hasConstrait($groupId)
    {
        return GroupUser::where('group_id', $groupId)->count() > 0 ||
            Role::where('group_id', $groupId)->count() > 0;
    }
}
